package pfsimulator;

import actors.{TIMEOUT, Actor}

/**
 * Created with IntelliJ IDEA.
 * User: codefish
 * Date: 11/4/12
 * Time: 12:00 PM
 * To change this template use File | Settings | File Templates.
 */

case class Throttle(rtBw: Long)
object Exit

class FlowRun(id: Long, s: Int, d: Int, bw: Long, size: Long, simulator: ParaflowSimulator) extends Actor{
    val flowId = id
    val srcPNodeIdx = s
    val dstPNodeIdx = d
    var rtBw = bw
    var remaining = size // in bytes
    val timeUnit = 500.toLong
    val ratioToSecond = timeUnit.toFloat/1000.toFloat

    val pfsimulator = simulator
    var isStarted = false
    var isEnded = false

    /*
    println("bw="+rtBw)
    println("size="+remaining)
    */
    // TODO
    def act() {
        var lastTick = System.currentTimeMillis()
        var waitTime = timeUnit
        isStarted = true

        loop {
            reactWithin(waitTime){
                case TIMEOUT =>
                    transfer()
                    resetClock()
                case Throttle(rtBw) =>
                    this.rtBw = rtBw
                    setClock()
                case Exit =>
                    exit
            }
        }

        // NOTE: CALL THIS FUNCTION EVERY TIME I GET A MSG THAT IS NOT TO
        def setClock(){
            waitTime = timeUnit-(System.currentTimeMillis()-lastTick)
        }
        def resetClock(){
            lastTick = System.currentTimeMillis()
            waitTime = timeUnit
        }
        def transfer(){
            if (isEnded == false){
                remaining -= (ratioToSecond*rtBw).toLong
                /*
                println(remaining +  " remains")
                */
                if (remaining <= 0){
                    reportFlowFinished()
                    isEnded = true
                }
            }
        }
        def reportFlowFinished(){
            ParaflowSimulator.LOG.info("Flow " + flowId + " is done")
            pfsimulator.addFlowFinishEvent(flowId)
        }
    }

    //
    // APIs, called by paraflowsimulator
    //  - send myself corresponding msgs
    //

    def run(){
        this.start()
    }

    def suspend(){
        // TODO
    }

    def resume(){
        // TODO
    }

    def throttle(rate: Long){
        this ! Throttle(rate)
    }

    def stop(){
        // TODO
        this ! Exit
    }

    def getSrcIdx(): Int = {
        return srcPNodeIdx
    }
    def getDstIdx(): Int = {
        return dstPNodeIdx
    }
    def getRtBw(): Long = {
        return rtBw
    }
}

object FlowRun{
}

